"""
下拉框小部件。
"""
import typing
from ..framework import dispatch, session_received
from ..base import BaseSession, BaseSessionType, BaseSessionParentType
from .base import BaseWidget
from ..utils import Any, BoolValue, Int32Value, callback, from_any, to_any


@session_received
class WidgetSpinner(BaseSession, BaseWidget):
    """
    下拉框小部件。
    """
    name = 'WidgetSpinner'

    @classmethod
    async def create(cls: typing.Type[BaseSessionType], parent: BaseSessionParentType,
                     *args: typing.Any, **kwargs: typing.Dict) -> BaseSessionType:
        """
        五个参数：
        @width: 宽度；
        @height: 高度；
        @x: 左上角横坐标；
        @y: 左上角纵坐标；
        @dialog_mode: 对话框模式为True，下拉模式为False，默认为False。
        使用方法：
        spinner = await WidgetSpinner.create(activity, 200, 50, 0, 0)
        """
        dialog_mode = to_any(args[4] if len(args) > 4 else False, BoolValue)
        return await super().create(parent, *cls.parse_region(*args), dialog_mode, **kwargs)

    async def on_receive(self, msg):
        """
        组件的事件转发。
        """
        await super().on_receive(msg)
        name, sid, fid, argv = msg.name, msg.session, msg.future, msg.argv
        if name == 'onGetPrompt':
            dispatch(self.on_get_prompt(*argv, session_id=sid, future_id=fid))
        else:
            dispatch(super().on_widget_action(*argv, name=name, session_id=sid, future_id=fid))

    @callback(str)
    async def on_get_prompt(self, prompt, session_id=0, future_id=0):
        """
        当获取下拉框的提示信息成功后，此方法被自动调用。
        通常不需要关注此方法的实现。
        """
        if not session_id:
            return
        self.set_action_result(session_id, future_id, prompt)

    async def get_prompt(self) -> str:
        """
        获取下拉框的提示信息。
        调用示例：
        print(await spinner.get_prompt())
        """
        return await self.send_action_until_return('getPrompt')

    async def set_prompt(self, prompt: str):
        """
        给下拉框设置提示信息，只在对话框模式下起作用，当对话框弹出时作为标题显示。
        :param prompt: 提示给用户的信息文字。
        调用示例：
        await spinner.set_prompt('请选择类型')
        """
        dispatch(self.send_action('setPrompt', to_any(prompt)))

    async def select(self, index: int):
        """
        选中下拉框某一项。
        :param index: 项目索引，从0开始。
        调用示例：
        await spinner.select(0)
        """
        dispatch(self.send_action('select', to_any(index)))

    async def set_items(self, items: typing.List[str] | typing.Tuple[str]):
        """
        给下拉框设置数据。
        :param items: 在下拉框打开时展示的数据。
        调用示例：
        await spinner.set_items(['分类1', '分类2'])
        """
        dispatch(self.send_action('setItems', *[to_any(i) for i in items]))

    async def set_on_item_selected_listener(self, func: typing.Optional[typing.Callable] = None):
        """
        设置下拉框某个项目被用户选择时的监听函数。
        :param func: 一个可调用的异步函数对象（需要实现index: int参数），如果是None则取消监听函数。
        调用示例：
        async def cb(index: int): ...
        await spinner.set_on_item_selected_listener(cb)
        """
        if not func:
            dispatch(self.send_action('setOnItemSelectedListener', to_any(None)))
            return

        async def _func(index: Any):
            """
            回调监听代理函数。
            index: 选中的项目索引，从0开始。
            """
            if func:
                await func(from_any(index, Int32Value))

        dispatch(self.send_action('setOnItemSelectedListener', self.create_callback(_func)))
